C.S.Burner πͺ ββΊπ₯GIT Node
docs/en/plugins.md dev (8f381c86) Text, 9.42 KB
Plugins
Plugins extend MeshChatX with extra tools, nav items, and background behaviour. They are capability-gated: a plugin only gets what you grant at install time.
Manage them from Settings β Plugins. Disable every packaged plugin at startup with T383838--disable-plugins or T383838MESHCHAT_DISABLE_PLUGINS=true.
What plugins can do
β’ Add a row on the Tools page
β’ Add an item in the main Navigation sidebar
β’ React to mesh events (announces, RNS link traffic)
β’ Call narrowly declared backend managers (path table, debug log, bug reports, RNS links)
β’ Keep a private key-value store (T383838storage: isolated)
β’ Optionally fetch clearnet HTTP (T383838network: fetch), still subject to Privacy mode
Plugins cannot rewrite core MeshChatX. They do not get open-ended filesystem or process control unless you opt into Sideband Python plugins (see below).
Runtimes
ββββββββββββββββββ¬ββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββ
β Runtime β Where it runs β Trust level β
ββββββββββββββββββΌββββββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββ€
β Frontend JS β Browser Web Worker β Medium. Sandboxed worker, capability grants β
β Backend WASM β T383838wasmtime on the server β Medium. Fuel-metered, capability-gated host β
β Backend Python β In-process with MeshChatX β High. Permission-checked in-process host β
β Sideband T383838*.py β In-process, flat files β Highest. Opt-in danger switch, full host access β
ββββββββββββββββββ΄ββββββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββ
A packaged plugin can ship frontend only, backend only, or both.
Install flow
T282828
Pick ZIP or .wasm file in Settings β Plugins
|
--> Preview (permissions, URLs, signature, findings)
|
--> You grant or deny each capability
|
--> Optional: trust a valid signer
|
--> Install + integrity hash stored
|
--> Enable
|
--> Frontend Worker loads (if present)
--> Backend WASM / Python activates (if present)
Invalid signatures hard-block install. Unsigned packages are allowed. Present-but-broken signatures are not.
After install, MeshChatX hashes the on-disk tree. If files change outside the app, the plugin is auto-disabled as tampered.
Bundled example: Bug Reports
T383838com.meshchatx.mcx-bugs ships with MeshChatX. It adds a Bug Reports tool for sending redacted debug logs to an T383838mcx-bugs-v1 collector, or running a collector yourself.
Layout:
T282828
mcx-bugs/
plugin.json
frontend/main.js
backend/main.py
locales/en.json
Use it as the reference package when building your own.
Manifest (T383838plugin.json)
Every packaged plugin needs a root T383838plugin.json.
T282828
Tb4b4b4{
Tff7b72"id"Tb4b4b4: Ta5d6ff"com.example.my-plugin"Tb4b4b4,
Tff7b72"version"Tb4b4b4: Ta5d6ff"1.0.0"Tb4b4b4,
Tff7b72"apiVersion"Tb4b4b4: T79c0ff1Tb4b4b4,
Tff7b72"name"Tb4b4b4: Ta5d6ff"My Plugin"Tb4b4b4,
Tff7b72"description"Tb4b4b4: Ta5d6ff"Adds a custom tool."Tb4b4b4,
Tff7b72"frontend"Tb4b4b4: Tb4b4b4{
Tff7b72"entry"Tb4b4b4: Ta5d6ff"frontend/main.js"Tb4b4b4,
Tff7b72"type"Tb4b4b4: Ta5d6ff"js"
Tb4b4b4},
Tff7b72"backend"Tb4b4b4: Tb4b4b4{
Tff7b72"entry"Tb4b4b4: Ta5d6ff"backend/main.py"Tb4b4b4,
Tff7b72"type"Tb4b4b4: Ta5d6ff"python"
Tb4b4b4},
Tff7b72"i18n"Tb4b4b4: Tb4b4b4{
Tff7b72"directory"Tb4b4b4: Ta5d6ff"locales"Tb4b4b4,
Tff7b72"defaultLocale"Tb4b4b4: Ta5d6ff"en"
Tb4b4b4},
Tff7b72"contributes"Tb4b4b4: Tb4b4b4{
Tff7b72"navItems"Tb4b4b4: Tb4b4b4[
Tb4b4b4{
Tff7b72"id"Tb4b4b4: Ta5d6ff"my-plugin"Tb4b4b4,
Tff7b72"route"Tb4b4b4: Tb4b4b4{ Tff7b72"name"Tb4b4b4: Ta5d6ff"plugin-my-plugin" Tb4b4b4},
Tff7b72"icon"Tb4b4b4: Ta5d6ff"puzzle"Tb4b4b4,
Tff7b72"labelKey"Tb4b4b4: Ta5d6ff"nav"
Tb4b4b4}
Tb4b4b4],
Tff7b72"toolsPageEntries"Tb4b4b4: Tb4b4b4[
Tb4b4b4{
Tff7b72"name"Tb4b4b4: Ta5d6ff"my-plugin"Tb4b4b4,
Tff7b72"route"Tb4b4b4: Tb4b4b4{ Tff7b72"name"Tb4b4b4: Ta5d6ff"plugin-my-plugin" Tb4b4b4},
Tff7b72"icon"Tb4b4b4: Ta5d6ff"puzzle"Tb4b4b4,
Tff7b72"titleKey"Tb4b4b4: Ta5d6ff"title"Tb4b4b4,
Tff7b72"descriptionKey"Tb4b4b4: Ta5d6ff"description"
Tb4b4b4}
Tb4b4b4]
Tb4b4b4},
Tff7b72"permissions"Tb4b4b4: Tb4b4b4{
Tff7b72"hooks"Tb4b4b4: Tb4b4b4[Ta5d6ff"announce.received"Tb4b4b4],
Tff7b72"managers"Tb4b4b4: Tb4b4b4[Ta5d6ff"destinationPath.read"Tb4b4b4],
Tff7b72"storage"Tb4b4b4: Ta5d6ff"isolated"Tb4b4b4,
Tff7b72"network"Tb4b4b4: Ta5d6ff"none"
Tb4b4b4}
Tb4b4b4}
Notes:
β’ T383838id is reverse-DNS style and must stay stable across versions
β’ T383838apiVersion is currently T3838381
β’ Plugin strings live in the plugin bundle (T383838locales/{locale}.json), not core T383838en.json
β’ T383838contributes wires UI slots through the frontend registries
Permissions
Nothing is available unless it is declared in the manifest and granted in the install dialog.
Hooks
βββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Hook β When it fires β
βββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β T383838announce.received β A Reticulum announce arrives β
β T383838rns.link.event β Generic RNS Link traffic (T383838packet_received, T383838link_closed) β
βββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Hook events reach the UI as WebSocket T383838plugin.event frames, then into the plugin Worker.
Managers
ββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββ
β Manager β Purpose β
ββββββββββββββββββββββββΌββββββββββββββββββββββββββββββββ€
β T383838destinationPath.read β Read the Reticulum path table β
β T383838debugLog.read β Read redacted debug logs β
β T383838bugReport.* β Bug report / collector APIs β
β T383838rnsLink.open β Open or reuse an RNS link β
β T383838rnsLink.identify β Identify on a cached link β
β T383838rnsLink.request β Request/response on a link β
β T383838rnsLink.send β Send a raw link packet β
β T383838rnsLink.close β Tear down a cached link β
ββββββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββ
Call managers from a plugin with T383838POST /api/v1/plugins/{id}/invoke and T383838method: "callManager". Details for the link transport are in RNS Link API.
Storage and network
βββββββββββββββββββββ¬ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Permission β Effect β
βββββββββββββββββββββΌββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ€
β T383838storage: isolated β Private key-value store in the MeshChatX database β
β T383838storage: none β No plugin storage β
β T383838network: fetch β Outbound HTTP allowed (still blocked by Privacy mode when that is on) β
β T383838network: none β No clearnet fetch β
βββββββββββββββββββββ΄ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Install preview also scans plugin files for external T383838http:// / T383838https:// URLs and shows them before you grant network access.
How a frontend plugin runs
T282828
Settings enable plugin
|
--> PluginHost loads /api/v1/plugins
|
--> Fetch frontend entry as text
|
--> Spawn pluginWorker.js (module Worker)
|
--> Register nav / tools contributions
|
--> Subscribe to plugin.event on /ws (if hooks granted)
|
--> Worker may invoke backend via /api/v1/plugins/{id}/invoke
The Worker talks to the host with typed messages (T383838init, T383838event, T383838request). The host never gives the Worker a raw privileged API.
How a backend plugin runs
T282828
Enable plugin
|
+--> type: wasm --> load into wasmtime, fuel + host caps
|
+--> type: python --> import entry, call activate(host)
|
--> Hooks fan out from PluginManager
|
--> invoke(method, args) for RPC from the UI Worker
Python host surface (permission-checked):
β’ T383838host.log(message)
β’ T383838host.call_manager(capability, args)
β’ T383838host.storage_get(key) / T383838host.storage_set(key, value)
β’ T383838host.network_fetch_allowed()
Packaging and signing
Distribute as:
1. ZIP with T383838plugin.json and assets
2. WASM bundle (single T383838.wasm with embedded manifest / files / optional signature)
Signature file for ZIP/dir packages: T383838meshchatx.plugin.rsg
WASM custom sections:
T282828
meshchatx.plugin --> embedded plugin.json
meshchatx.files --> embedded text assets
meshchatx.signature --> RSG over payload without this section
Canonical ZIP signing uses sorted paths and fixed 1980-01-01 mtimes. The signature file itself is excluded from the signed payload.
Sign and verify with:
T282828
python3 scripts/sign-plugin.py sign-dir ./my-plugin --identity <rnid>
python3 scripts/sign-plugin.py verify-dir ./my-plugin
python3 scripts/sign-plugin.py sign-zip ./my-plugin.zip --identity <rnid>
python3 scripts/sign-plugin.py sign-wasm ./plugin.wasm --identity <rnid>
python3 scripts/sign-plugin.py sign-py ./legacy_plugin.py --identity <rnid>
Trust status in the UI:
T282828
No .rsg present
--> Unsigned (install allowed)
Valid .rsg, signer unknown
--> Signed (you can add to Trusted Publishers)
Valid .rsg, signer in Trusted Publishers
--> Trusted
Broken / mismatched .rsg
--> Invalid (install blocked)
Sideband-compatible plugins
Legacy Sideband-style flat T383838*.py files are separate from packaged ZIP/WASM plugins.
T282828
Settings β Plugins β Sideband
|
--> Confirm danger prompt
|
--> Set directory of *.py files
|
--> Optional filename.py.rsg next to each script
|
--> Reload
These run in-process with full host access. They are not ZIP-permission gated. Keep the master switch off unless you trust every file in that directory.
Operator tips
β’ Prefer signed packages from publishers you added yourself
β’ Deny T383838network: fetch unless the plugin needs clearnet HTTP
β’ Prefer WASM backends over Python when you can
β’ Use T383838--disable-plugins when diagnosing weird UI or backend behaviour
β’ Treat Sideband plugins like running arbitrary local scripts
See also
β’ Tools and utilities for the Tools page and contribution overview
β’ Architecture and design for the plugin runtime overview
β’ Identities, privacy, and security for signing and Privacy mode
Served by rngit 1.3.7 - Generated in 0.03s